home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / plan / src / cyccalc.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  5KB  |  160 lines

  1. /*
  2.  * Move the date of entries that have recycling information to the next
  3.  * trigger date.
  4.  *
  5.  *    length_of_month(time)        Return the # of days in the month
  6.  *                    <time> [#secs since 1/1/70] is in
  7.  *    recycle_all(list, del, days)    Calls recycle() for all entries
  8.  *                    in <list>, and optionally deletes
  9.  *                    obsolete (expired) entries.
  10.  *    recycle(entry, date, ret)    If <entry> cycles, return its next
  11.  *                    trigger time after or on <date>,
  12.  *                    and find out if it is now obsolete.
  13.  */
  14.  
  15. #include <time.h>
  16. #include <Xm/Xm.h>
  17. #include "cal.h"
  18.  
  19. int recycle();
  20. extern struct tm *time_to_tm();
  21. extern time_t get_time();
  22.  
  23. extern struct config    config;        /* global configuration data */
  24.  
  25.  
  26. /*
  27.  * return the number of seconds in the month that <time> falls into. This
  28.  * routine overwrites the static tm buffer.
  29.  */
  30.  
  31. time_t length_of_month(time)
  32.     time_t            time;        /* some date in the month */
  33. {
  34.     struct tm        *tm;        /* time to m/d/y conv */
  35.  
  36.     tm = time_to_tm(time);
  37.     time -= (tm->tm_mday-1) * 86400;
  38.     tm->tm_mday = 1;
  39.     if (tm->tm_mon++ == 11) {
  40.         tm->tm_mon = 0;
  41.         tm->tm_year++;
  42.     }
  43.     return(tm_to_time(tm) - time);
  44. }
  45.  
  46.  
  47. /*
  48.  * scan the entire list and remove obsolete entries, and recycle repeating
  49.  * entries. This is called regularly. Return TRUE if something changed. If
  50.  * TRUE is returned, the caller must call draw_calendar() and
  51.  * update_all_listmenus().
  52.  */
  53.  
  54. BOOL recycle_all(list, del, days)
  55.     struct list        *list;        /* list to scan */
  56.     BOOL            del;        /* auto-remove obolete? */
  57.     int            days;        /* if del, keep if age < days*/
  58. {
  59.     int            n;        /* entry counter */
  60.     time_t            now;        /* current time */
  61.     time_t            time;        /* next trigger time */
  62.     BOOL            chg = FALSE;    /* TRUE if list was changed */
  63.  
  64.     now = get_time();
  65.     for (n=0; n < list->nentries; n++)
  66.         switch(recycle(&list->entry[n], now, &time)) {
  67.           case 2:
  68.             if (del && now - time > days * 86400) {
  69.                 delete_entry(list, n--);
  70.                 chg = TRUE;
  71.             }
  72.             break;
  73.  
  74.           case 1:
  75.             if (time > list->entry[n].time) {
  76.                 list->entry[n].time = time;
  77.                 resort_entry(list, n--);
  78.                 chg = TRUE;
  79.             }
  80.             break;
  81.         }
  82.     if (chg)
  83.         rebuild_repeat_chain(list);
  84.     return(chg);
  85. }
  86.  
  87.  
  88. /*
  89.  * If the entry has recycling info, move it up to the next date it triggers.
  90.  * Searching for the next trigger date if multiple repeat restrictions are
  91.  * set is very messy, I am using a trial-and-error approach for now.
  92.  * Set *ret to the time the entry will trigger next after <date>, and return
  93.  *
  94.  *  0    if the entry didn't change and doesn't trigger,
  95.  *  1    if the entry is triggering on or after date; trigger time is in *ret,
  96.  *  2    if the entry has become obsolete (24 hours after last trigger time).
  97.  */
  98.  
  99. recycle(entry, date, ret)
  100.     register struct entry    *entry;        /* entry to test */
  101.     time_t            date;        /* today (time is ignored) */
  102.     register time_t        *ret;        /* returned next trigger time*/
  103. {
  104.     struct tm        tm1;        /* first trigger m/d/y ever */
  105.     struct tm        tm;        /* time to m/d/y h:m:s conv */
  106.     time_t            day;        /* <date> with no time info */
  107.     long            eday;        /* entry date with no time */
  108.     long            end;        /* don't search too far */
  109.     long            every;        /* period in days */
  110.     int            mlen = 0;    /* # of days in test month */
  111.     register long        w = entry->rep_weekdays;
  112.     register long        d = entry->rep_days;
  113.     register time_t        l = entry->rep_last;
  114.  
  115.     *ret = entry->time;
  116.     eday = *ret / 86400;
  117.     day  = date / 86400;
  118.     end  = date + 86400 * 32;
  119.     if (day < eday)
  120.         return(0);
  121.     if (l && *ret > l + 86400-1)
  122.         return(2);
  123.     if (!entry->rep_every && !entry->rep_yearly && !w && !d)
  124.         return(date < *ret || date - *ret < 86400 ? 0 : 2);
  125.     if (entry->rep_every && !((day - eday) % (entry->rep_every/86400))) {
  126.         *ret %= 86400;
  127.         *ret += date - date % 86400;
  128.         return(l && *ret > l + 86400-1 ? 2 : 1);
  129.     }
  130.     if (entry->rep_yearly)
  131.         tm1 = *time_to_tm(entry->time);
  132.     every = entry->rep_every && !entry->rep_yearly ?
  133.                         entry->rep_every / 86400 : 1;
  134.     *ret += ((day - eday + every-1) / every) * every * 86400;
  135.     while (*ret < end) {
  136.         tm = *time_to_tm(*ret);
  137.         if (l && *ret > l + 86400-1)
  138.             return(2);
  139.         if (entry->rep_yearly && tm.tm_mon  == tm1.tm_mon
  140.                       && tm.tm_mday == tm1.tm_mday)
  141.             return(1);
  142.         if (entry->rep_every && *ret > date + entry->rep_every + 86400)
  143.             return(0);
  144.         if ((d & 1) || (w & 0x2000))
  145.             mlen = length_of_month(*ret) / 86400;
  146.         if (w & 1 << tm.tm_wday) {
  147.             if (!(w & 0x3f00))
  148.                 return(1);
  149.             if ((w & 0x0100 << (tm.tm_mday-1) / 7) ||
  150.                 (w & 0x2000) && tm.tm_mday+7 > mlen)
  151.                 return(1);
  152.         }
  153.         if ((d & 1 << tm.tm_mday) ||
  154.             (d & 1) && tm.tm_mday == mlen)
  155.                  return(1);
  156.         *ret += every * 86400;
  157.     }
  158.     return(*ret >= date && *ret < date + 86400 ? 1 : 0);
  159. }
  160.